﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Reflection;
using OpenNETCF.IoC;

namespace OpenNETCF.MTConnect
{
    public class InstanceService : IInstanceService
    {
        public List<IAdapterInstanceInfo> AdapterInstanceInfos { get; set; }

        public InstanceService()
        {
            Load();
        }

        private static string GetConfigFilePath()
        {
            var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
            if (path.StartsWith("file:\\")) path = path.Substring(6);
            return Path.Combine(path, "AdapterInstances.xml");
        }


        public List<string> GetAdapterInstanceNames(string name)
        {
            foreach (var adapterInstanceInfo in AdapterInstanceInfos)
            {
                if (name == adapterInstanceInfo.AdapterName)
                {
                    return adapterInstanceInfo.InstanceNames;
                }
            }
            return null;
        }

        private IAdapterInstanceInfo FindAdapter(string name)
        {
            foreach (var adapterInstanceInfo in AdapterInstanceInfos)
            {
                if (name == adapterInstanceInfo.AdapterName)
                {
                    return adapterInstanceInfo;
                }
            }

            var loadedAdapters = RootWorkItem.Services.Get<IHostedAdapterService>().LoadedAdapters;

            foreach (var adapter in loadedAdapters)
            {
                if (adapter.ID == name)
                {
                    var instanceInfo = new AdapterInstanceInfo(name);
                    AdapterInstanceInfos.Add(instanceInfo);
                    return instanceInfo;
                }
            }

            return null;
        }

        public bool AddAdapterInstance(string adapterName, string instanceName)
        {
            var adapterInstanceInfo = FindAdapter(adapterName);
            if( adapterInstanceInfo == null )
            {
                adapterInstanceInfo = new AdapterInstanceInfo(adapterName);
                AdapterInstanceInfos.Add(adapterInstanceInfo);
            }

            if (adapterInstanceInfo.InstanceNames.Contains(instanceName))
            {
                return false;
            }
            else
            {
                adapterInstanceInfo.InstanceNames.Add(instanceName);
                IHostedAdapterService hostedAdapterService = RootWorkItem.Services.Get<IHostedAdapterService>();
                hostedAdapterService.LoadInstance(adapterName, instanceName);
            }

            Save(); 
            
            return true;
        }

        public bool RemoveAdapterInstance(string adapterName, string instanceName)
        {
            var adapterInstanceInfo = FindAdapter(adapterName);
            if( adapterInstanceInfo == null )
            {
                return false;
            }

            if( adapterInstanceInfo.InstanceNames.Contains(instanceName))
            {
                adapterInstanceInfo.InstanceNames.Remove(instanceName);
                IHostedAdapterService hostedAdapterService = RootWorkItem.Services.Get<IHostedAdapterService>();
                hostedAdapterService.RemoveInstance(adapterName, instanceName);

                if( adapterInstanceInfo.InstanceNames.Count == 0 )
                {
                    AdapterInstanceInfos.Remove(adapterInstanceInfo);
                    hostedAdapterService.RemoveAdapter(adapterName);
                }
                Save();
                return true;
            }
            return true;
        }

        public bool Load()
        {
            AdapterInstanceInfos = new List<IAdapterInstanceInfo>();
            if (File.Exists(GetConfigFilePath()))
            {
                XDocument doc = new XDocument();
                try
                {
                    doc = XDocument.Load(GetConfigFilePath());

                    foreach (var element in doc.Element("AdapterInstanceInfos").Elements())
                    {
                       string adapterName = element.Attribute("AdapterName").Value;
                        
                       if (element.Name == "AdapterInstanceInfo")
                        {
                            var adapterInfo = new AdapterInstanceInfo(adapterName);

                            foreach (var instanceElement in element.Elements())
                            {
                                if (instanceElement.Name == "InstanceName")
                                {
                                    if (instanceElement.Value != null && instanceElement.Value.Length > 0)
                                    {
                                        adapterInfo.InstanceNames.Add(instanceElement.Value);
                                    }
                                }
                            }
                            AdapterInstanceInfos.Add(adapterInfo);
                        }
                    }

                    return true;
                }
                catch
                {
                    return false;
                }
            }
            else
            {
                SetDefaults();
                return false;
            }
        }

        public void SetDefaults()
        {
            var adapterInstanceInfo = new AdapterInstanceInfo("MachineAdapter");
            //adapterInstanceInfo.InstanceNames.Add("Lathe1");
            AdapterInstanceInfos.Add(adapterInstanceInfo);

            adapterInstanceInfo = new AdapterInstanceInfo("ManagementAdapter");
            //adapterInstanceInfo.InstanceNames.Add("Lathe1-Management");
            AdapterInstanceInfos.Add(adapterInstanceInfo);
            
            Save();
        }

        public void Save()
        {
            XDocument doc = new XDocument();

            XElement adapterInstanceInfos = new XElement("AdapterInstanceInfos");

            foreach (var adapterInstanceInfo in AdapterInstanceInfos)
            {
                XElement adapterInstanceInfoElement = new XElement("AdapterInstanceInfo");
                adapterInstanceInfoElement.AddAttribute( "AdapterName", adapterInstanceInfo.AdapterName);
                foreach (var adapterInstanceName in adapterInstanceInfo.InstanceNames)
                {
                    XElement instanceNameElement = new XElement("InstanceName");
                    instanceNameElement.Value = adapterInstanceName;
                    adapterInstanceInfoElement.Add(instanceNameElement);
                }
                adapterInstanceInfos.Add(adapterInstanceInfoElement);
            }

            doc.Add(adapterInstanceInfos);
            doc.Save(GetConfigFilePath());
        }
    }
}
